﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swcommands;
using SolidWorks.Interop.swconst;
using SolidWorks.Interop.swpublished;

using SwAddinHelpers.Contracts;
using SwAddinHelpers.Attributes;
using SwAddinHelpers;
using SwAddinHelpers.Base;
using SwAddinHelpers.Sinks;

namespace SwAddinHelpers.ModelView
{
    public sealed class ModelViewTabHost: UserControlHostBase
    {
        private ModelViewManager _ModelViewManager;

        public ModelViewManager ModelViewManager
        {
            get { return _ModelViewManager; }
        }

        private string _UniqueTabName;
        private bool _IsSplit;
        private bool _AutoGenView;
        private bool _NotifyUserOfCreationFailure;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="externalControl"></param>
        /// <param name="UniqueTabName"></param>
        /// <param name="IsSplit">If false then the control takes up the entire model view region.</param>
        /// <param name="AutoGenView"></param>
        /// <param name="NotifyUserOfCreationFailure"></param>
        public ModelViewTabHost(ISwAddinBase owner, IExternalUserControl externalControl, string UniqueTabName,  bool IsSplit = true, bool AutoGenView = true, bool NotifyUserOfCreationFailure = false)
        {
            _OwnerAddin = owner;

            _UniqueTabName = UniqueTabName;
            _IsSplit = IsSplit;
            _NotifyUserOfCreationFailure = NotifyUserOfCreationFailure;
            _AutoGenView = AutoGenView;

            base.externalControl = externalControl.ExternalUserControl;

            if (_AutoGenView)
            {
               this.SubscribeEvent(enumEventSink.SW_ActiveModelDocChangeNotify, enumEventSubscriptionSource.GUI_HOST);
               this.SubscribeEvent(enumEventSink.Document_DestroyNotify, enumEventSubscriptionSource.GUI_HOST);
            }
            
        }

        /// <summary>
        /// Notified with the PathOrTitle and CreateDate of the previously active model.
        /// </summary>
        /// <param name="sender"></param>
        [SinkMethod(enumEventSink.Custom_ActiveModelDocChangePreNotify)]
        void ActiveModelDocChangePreNotfiy(object sender, SolidWorksEventArgs e)
        {
            if (_ModelViewManager != null)
            {
                // here we check if the current modelviewmanager holds a reference 
                //   to the previously active document

                //TODO
                // Each uc host could expose a ModelDoc2 that it owns.
                // then the main sinnk could call the correct uc host instead of all of them
                // this would move the below logic to the main sink.
                //
                
                // hold on, this method isn't really needed
                // since only one MVH1 host exist across the addin then 
                // once the docactivate gets called, the modelviewmgr gets deleted
                // and replaced with the current doc's modelviewmgr

                /*
                string a = _ModelViewManager.Document.GetPathName();
                //todo: below line threw rpc_disc !
                if (a.Length == 0) a = _ModelViewManager.Document.GetTitle();
                string b = _ModelViewManager.Document.SummaryInfo[(int)swSummInfoField_e.swSumInfoCreateDate2];

                if (a.ToUpper() == e.ActiveDocChangePreNotify_PathOrTitle.ToUpper() &&
                    b.ToUpper() == e.ActiveDocChangePreNotify_CreateDate.ToUpper())
                {
                    DeleteModelViewTab();
                }
                 */

                // we can omit the above code and just call
                DeleteModelViewTab();
                // we can do this since the above will always be true.
            }
        }

        [SinkMethod(enumEventSink.SW_ActiveModelDocChangeNotify)]
        private void CreateModelViewTab(object sender, EventArgs e)
        {
            bool IsCreated = CreateModelViewTab(true);
            if ( _NotifyUserOfCreationFailure && !IsCreated)
            {
                MessageBox.Show("Failed to create model view tab " + HostedControlTypeProgId + " !");
            }
        }

        public bool CreateModelViewTab(bool Activate)
        {   
            // if we keep the activedoc-prenotify then we don't need to call deletemv here.
            //DeleteModelViewTab();

            this.SubscribeEvent(enumEventSink.Custom_ActiveModelDocChangePreNotify, enumEventSubscriptionSource.GUI_HOST);

            bool returns = false;

            try
            {
                string bmp = _OwnerAddin.DUMMYBMP;

                _ModelViewManager = _OwnerAddin.SolidWorksApplication.IActiveDoc2.ModelViewManager;

                _GuiControl = (UserControlBase)_ModelViewManager.AddControl3(_UniqueTabName, HostedControlTypeProgId, null, _IsSplit);
                _GuiControl.SetOwner = this;
                if (_GuiControl != null) _GuiControl.Tie();

                if (!_IsSplit)
                    _ModelViewManager.ActivateModelTab();
                else if (Activate)
                    _ModelViewManager.ActivateControlTab(_UniqueTabName);

                returns = true;
            }
            catch 
            {
                returns = false;
            }
            finally
            {
            }

            return returns;
        }

        [SinkMethod(enumEventSink.Document_DestroyNotify)]
        private void DeleteModelViewTab(object sender, SolidWorksEventArgs e)
        {
            DeleteModelViewTab();
        }

        public void DeleteModelViewTab()
        {
            if (_ModelViewManager != null)
            {
                this.UnsubscribeEvent(enumEventSink.Custom_ActiveModelDocChangePreNotify, enumEventSubscriptionSource.GUI_HOST);
                
                if (_GuiControl != null)
                {
                    _GuiControl.Untie();
                    _GuiControl = null;
                }

                try
                {
                    //TODO: sometimes it gets disconnected from RPC
                    //Marshal.ReleaseComObject(_ModelViewManager.GetControl(_UniqueTabName));
                    _ModelViewManager.DeleteControlTab(_UniqueTabName);
                }
                catch (COMException comEx)
                {

                }

                int holding = Marshal.ReleaseComObject(_ModelViewManager);
                //if (holding == 0)
                _ModelViewManager = null;
            }
        }

        public override void Teardown()
        {
            base.Teardown();

            DeleteModelViewTab();
        }

    }
}
